import hashlib
import os
import uuid

import openpyxl
from django.conf import settings
from django.core.exceptions import ObjectDoesNotExist
from django.core.paginator import Paginator, EmptyPage
from django.db.models import Q

from student.models import Student


class StudentService:
    """
    学生实现类
    """
    @staticmethod
    def get_students_with_pagination(data):
        """
        获取当前页学生信息
        """
        try:
            # 获取分页参数并设置默认值
            currentpage = int(data.get("currentpage", 1))
            pagesize = int(data.get("pagesize", 10))  # 默认每页 10 条
        except (ValueError, TypeError):
            raise ValueError("分页参数必须为整数")

        # 获取所有学生数据
        students = Student.objects.all()

        # 创建分页器
        paginator = Paginator(students, pagesize)
        try:
            # 获取指定页的数据
            page = paginator.page(currentpage)
        except EmptyPage:
            raise ValueError("页码超出范围")

        # 将查询集转换为列表
        student_list = []
        for student in page.object_list:
            student_list.append({
                'sno': student.sno,
                'name': student.name,
                'gender': student.gender,
                'birthday': student.birthday,
                'mobile': student.mobile,
                'email': student.email,
                'address': student.address,
                'image': student.image,
            })

        # 构建响应数据
        response_data = {
            'code': 1,
            'data': {
                'students': student_list,
                'page': {
                    'total_pages': paginator.num_pages,  # 总页数
                    'total_items': paginator.count,  # 学生总数
                    'page_size': pagesize,  # 每页显示的条目数
                }
            }
        }

        return response_data

    @staticmethod
    def query_students(data):
        """
        查询学生信息
        """
        try:
            # 定义查询参数
            query_params = [
                'sno',
                'name',
                'gender',
                'birthday',
                'mobile',
                'email',
                'address']
            query_dict = {param: data.get(param, '') for param in query_params}

            # 检查是否提供了任何查询条件
            if not any(query_dict.values()):
                raise ValueError("未提供任何查询条件")

            # 构建查询条件
            q_condition = Q()
            for field, value in query_dict.items():
                if value:
                    q_condition &= Q(**{f"{field}__icontains": value})

            # 执行查询并返回结果
            students = list(Student.objects.filter(q_condition).values())
            return {
                'code': 1,
                'data': students
            }

        except ValueError as ve:
            return {
                'code': 0,
                'msg': str(ve)
            }
        except Exception as e:
            return {
                'code': 0,
                'msg': f"查询学生信息出现异常，具体错误：{str(e)}"
            }

    @staticmethod
    def is_exists_sno(data):
        try:
            obj_students = Student.objects.filter(sno=data.get('sno', ''))
            return {'code': 1, 'exists': obj_students.exists()}
        except Exception as e:
            return {'code': 0, 'msg': '校验学号失败，具体原因：' + str(e)}

    @staticmethod
    def add_student(data):
        try:
            # 添加到数据库的逻辑
            obj_student = Student(
                sno=data.get('sno', ''),
                name=data.get('name', ''),
                gender=data.get('gender', ''),
                birthday=data.get('birthday', ''),
                mobile=data.get('mobile', ''),
                email=data.get('email', ''),
                address=data.get('address', ''),
                image=data.get('image', '')
            )
            obj_student.save()

            return {'code': 1}  # 返回需要的信息
        except Exception as e:
            return {'code': 0, 'msg': "添加到数据库出现异常，具体原因：" + str(e)}

    @staticmethod
    def update_student(data):
        try:
            # 查找要修改的学生信息
            sno = data.get('sno')
            if not sno:
                return {'code': 0, 'msg': '学号是必填参数'}

            obj_student = Student.objects.get(sno=sno)

            # 依次修改
            obj_student.name = data.get('name', obj_student.name)
            obj_student.gender = data.get('gender', obj_student.gender)
            obj_student.birthday = data.get('birthday', obj_student.birthday)
            obj_student.mobile = data.get('mobile', obj_student.mobile)
            obj_student.email = data.get('email', obj_student.email)
            obj_student.address = data.get('address', obj_student.address)
            obj_student.image = data.get('image', obj_student.image)

            # 保存
            obj_student.save()

            # 返回更新后的学生信息
            return {
                'code': 1
            }
        except ObjectDoesNotExist:
            return {'code': 0, 'msg': '学生信息不存在'}
        except Exception as e:
            return {'code': 0, 'msg': f"修改学生信息时出现异常：{str(e)}"}

    @staticmethod
    def delete_student(data):
        try:
            # 查找并删除学生信息
            sno = data.get('sno')
            if not sno:
                return {'code': 0, 'msg': '学号是必填参数'}

            obj_student = Student.objects.get(sno=sno)
            obj_student.delete()

            # 返回成功的消息和删除后的学生列表
            students = list(Student.objects.all().values())
            return {
                'code': 1,
                'data': students
            }
        except ObjectDoesNotExist:
            return {'code': 0, 'msg': '学生信息不存在'}
        except Exception as e:
            return {'code': 0, 'msg': f"删除学生信息时出现异常：{str(e)}"}

    @staticmethod
    def delete_students(data):
        try:
            # 获取要删除的学生列表
            students_to_delete = data.get('student', [])
            if not students_to_delete:
                return {'code': 0, 'msg': '未提供要删除的学生信息'}

            # 批量删除学生信息
            for one_student in students_to_delete:
                sno = one_student.get('sno')
                if sno:
                    try:
                        obj_student = Student.objects.get(sno=sno)
                        obj_student.delete()
                    except ObjectDoesNotExist:
                        continue  # 如果某个学生不存在，继续删除下一个

            # 返回成功的消息和删除后的学生列表
            students = list(Student.objects.all().values())
            return {
                'code': 1,
                'data': students
            }
        except Exception as e:
            return {'code': 0, 'msg': f"批量删除学生信息时出现异常：{str(e)}"}

    @staticmethod
    def upload_file(rev_file):
        try:
            if not rev_file:
                return {'code': 0, 'msg': '文件不存在！'}

            new_name = StudentService.get_random_str()
            file_path = os.path.join(
                settings.MEDIA_ROOT,
                new_name + os.path.splitext(rev_file.name)[1]
            )

            with open(file_path, 'wb') as f:
                for chunk in rev_file.chunks():
                    f.write(chunk)

            return {
                'code': 1,
                'name': new_name + os.path.splitext(rev_file.name)[1]
            }
        except Exception as e:
            return {'code': 0, 'msg': str(e)}

    @staticmethod
    def import_students_excel(rev_file):
        try:
            if not rev_file:
                return {'code': 0, 'msg': 'Excel文件不存在！'}

            new_name = StudentService.get_random_str()
            file_path = os.path.join(
                settings.MEDIA_ROOT,
                new_name + os.path.splitext(rev_file.name)[1]
            )

            with open(file_path, 'wb') as f:
                for chunk in rev_file.chunks():
                    f.write(chunk)

            # 读取Excel文件
            ex_students = StudentService.read_excel_dict(file_path)

            success = 0
            error = 0
            error_snos = []

            for one_student in ex_students:
                try:
                    Student.objects.create(
                        sno=one_student['sno'],
                        name=one_student['name'],
                        gender=one_student['gender'],
                        birthday=one_student['birthday'],
                        mobile=one_student['mobile'],
                        email=one_student['email'],
                        address=one_student['address']
                    )
                    success += 1
                except Exception:
                    error += 1
                    error_snos.append(one_student['sno'])

            # students = list(Student.objects.all().values())

            return {
                'code': 1,
                'success': success,
                'error': error,
                'errors': error_snos,
                # 'data': students
            }
        except Exception as e:
            return {'code': 0, 'msg': str(e)}
    @staticmethod
    def read_excel_dict(path):
        """读取Excel数据，存储为字典"""
        workbook = openpyxl.load_workbook(path)
        sheet = workbook['student']
        students = []
        keys = [
            'sno',
            'name',
            'gender',
            'birthday',
            'mobile',
            'email',
            'address']
        for row in sheet.iter_rows(min_row=1):  # 遍历每一行数据
            temp_dict = {}
            for index, cell in enumerate(row):  # 获取每个单元格及其索引
                if index < len(keys):
                    temp_dict[keys[index]] = cell.value
            students.append(temp_dict)
        return students

    @staticmethod
    def export_students_excel():
        try:
            # 获取所有学生信息
            students = list(Student.objects.all().values())

            # 生成随机文件名和文件路径
            excel_name = StudentService.get_random_str() + ".xlsx"
            file_path = os.path.join(settings.MEDIA_ROOT, excel_name)

            # 写入到Excel
            StudentService.write_to_excel(students, file_path)

            return {
                'code': 1,
                'name': excel_name
            }
        except Exception as e:
            return {
                'code': 0,
                'msg': str(e)
            }

    @staticmethod
    def get_random_str():
        """生成随机字符串"""
        uuid_val = uuid.uuid4()
        uuid_str = str(uuid_val).encode('utf-8')
        md5 = hashlib.md5()
        md5.update(uuid_str)
        return md5.hexdigest()

    @staticmethod
    def write_to_excel(data, path):
        """将数据写入Excel文件"""
        workbook = openpyxl.Workbook()
        sheet = workbook.active
        sheet.title = 'student'
        if data:
            keys = data[0].keys()
            for index, item in enumerate(data):
                for k, v in enumerate(keys):
                    sheet.cell(row=index + 1, column=k + 1, value=str(item[v]))
        workbook.save(path)


